package com.quectel.cms.controller.scheduling;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.cms.controller.BaseController;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.core.module.scheduling.dto.SchedulingTimeConfigDto;
import com.quectel.core.module.scheduling.service.SchedulingTimeConfigService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 *
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/07/05 13:24
 */
@RestController
@RequestMapping("schedulingTimeConfig")
@Tag(name = "SchedulingTimeConfigController", description = "考勤时间段配置相关api")
public class SchedulingTimeConfigController extends BaseController {

    @DubboReference
    private SchedulingTimeConfigService schedulingTimeConfigService;

    @PostMapping("updateStatus")
    @Operation(summary = "修改单条记录的状态")
    public Response<Object> updateStatus(@RequestBody SchedulingTimeConfigDto configDto) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(configDto.getId()));
        if (schedulingTimeConfigService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        //填充基础数据
        fillEditCommonData(configDto);

        schedulingTimeConfigService.updateById(configDto);

        return Response.ok();
    }

    @GetMapping("queryAll")
    @Operation(summary = "获取时间段列表")
    public Response<List<SchedulingTimeConfigDto>> queryAll() {
        //查询列表数据
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());

        request.put(LambdaUtil.getFieldName(SchedulingTimeConfigDto::getStatus),SystemConstants.YES);
        int total = schedulingTimeConfigService.queryTotal(request.getParams());

        List<SchedulingTimeConfigDto> list = null;
        if (total > 0) {
            list = schedulingTimeConfigService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        return Response.<List<SchedulingTimeConfigDto>>ok().wrap(list);
    }

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @RequirePermissions(values = "schedulingTimeConfig:list")
    @Operation(summary = "分页获取考勤时间段配置列表")
    public Response<Page<SchedulingTimeConfigDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = schedulingTimeConfigService.queryTotal(request.getParams());

        List<SchedulingTimeConfigDto> list = null;
        if (total > 0) {
            list = schedulingTimeConfigService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<SchedulingTimeConfigDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<SchedulingTimeConfigDto>>ok().wrap(page);
    }

    /**
     * 编辑查询反显
     *
     * @param id
     * @return
     */
    @GetMapping("infoForEdit/{id}")
    @RequirePermissions(values = "schedulingTimeConfig:edit")
    @Operation(summary = "在编辑时根据id查询考勤时间段配置详情")
    public Response<SchedulingTimeConfigDto> infoForEdit(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (schedulingTimeConfigService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        SchedulingTimeConfigDto schedulingTimeConfigDto = schedulingTimeConfigService.selectById(id);

        return Response.<SchedulingTimeConfigDto>ok().wrap(schedulingTimeConfigDto);
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "schedulingTimeConfig:info")
    @Operation(summary = "根据id查询考勤时间段配置的详情")
    public Response<SchedulingTimeConfigDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (schedulingTimeConfigService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        SchedulingTimeConfigDto schedulingTimeConfigDto = schedulingTimeConfigService.selectById(id);

        return Response.<SchedulingTimeConfigDto>ok().wrap(schedulingTimeConfigDto);
    }

    /**
     * 保存
     *
     * @param schedulingTimeConfigDto
     * @return
     */
    @PostMapping("save")
    @RequirePermissions(values = "schedulingTimeConfig:edit")
    @Operation(summary = "新增考勤时间段配置")
    public Response<Object> save(@RequestBody @Validated SchedulingTimeConfigDto schedulingTimeConfigDto) throws ParseException {
        Response<Object> response = validateTimeConfig(schedulingTimeConfigDto);
        if (!response.isSuccess()) {
            return response;
        }

        //填充基础数据
        fillSaveCommonData(schedulingTimeConfigDto);

        schedulingTimeConfigService.save(schedulingTimeConfigDto);

        return Response.ok();
    }


    /**
     * 修改
     *
     * @param schedulingTimeConfigDto
     * @return
     */
    @PostMapping("update")
    @RequirePermissions(values = "schedulingTimeConfig:edit")
    @Operation(summary = "根据id修改考勤时间段配置")
    public Response<Object> update(@RequestBody  @Validated SchedulingTimeConfigDto schedulingTimeConfigDto) throws ParseException {
        Response<Object> response = validateTimeConfig(schedulingTimeConfigDto);
        if (!response.isSuccess()) {
            return response;
        }

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(schedulingTimeConfigDto.getId()));
        if (schedulingTimeConfigService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        //填充基础数据
        fillEditCommonData(schedulingTimeConfigDto);

        schedulingTimeConfigService.updateById(schedulingTimeConfigDto);

        return Response.ok();
    }

    /**
     * 校验时间段
     *
     * @param schedulingTimeConfigDto
     * @return
     * @throws ParseException
     */
    private Response<Object> validateTimeConfig(SchedulingTimeConfigDto schedulingTimeConfigDto) throws ParseException {
        // 1.按照顺序放入相应列表
        List<String> times = new ArrayList<>();
        times.add(schedulingTimeConfigDto.getStartSignTime());
        times.add(schedulingTimeConfigDto.getWorkTime());
        times.add(schedulingTimeConfigDto.getLateTime());
        times.add(schedulingTimeConfigDto.getMissingWorkTime());
        times.add(schedulingTimeConfigDto.getMissingClosingTime());
        times.add(schedulingTimeConfigDto.getEarlyLeaveTime());
        times.add(schedulingTimeConfigDto.getClosingTime());
        times.add(schedulingTimeConfigDto.getEndSignTime());

        // 2.开始判断时间段配置
        // 2.1找到时间变小的坐标，并重新处理（可能跨天，跨天的情况需要对跨天以后的日期加一天）
        int descIndex = 0;
        String tempTime = times.get(0);
        for (int i = 1; i < times.size(); i++) {
            if (tempTime.compareTo(times.get(i)) > 0) {
                descIndex = i;
                break;
            }
            tempTime = times.get(i);
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");

        // 2.2开始转换时间
        List<Date> convertedTimes = new ArrayList<>();
        for (int i = 0; i < times.size(); i++) {
            if (descIndex == 0 || i < descIndex) {
                // 全部没有降序 或者 在降序之前都是当天
                convertedTimes.add(simpleDateFormat.parse(times.get(i)));
            } else {
                // 跨天时间+1
                Date parse = simpleDateFormat.parse(times.get(i));
                convertedTimes.add(new Date(parse.getTime() + 24L * 60 * 60 * 1000));
            }
        }
        // 2.3处理后的时间开始比较 出现一个降序则有问题
        Date tempDate = convertedTimes.get(0);
        for (int i = 1; i < convertedTimes.size(); i++) {
            if (tempDate.getTime() > convertedTimes.get(i).getTime()) {
                return Response.error("时间段配置出错");
            }
            tempDate = convertedTimes.get(i);
        }

        // 3.判断工作总时长是否超过24小时
        final long workTime = convertedTimes.get(1).getTime();
        final long closeTime = convertedTimes.get(6).getTime();
        if (closeTime - workTime >= 24L * 60 * 60 * 1000) {
            return Response.error("上班时间段必须要小于24小时");
        }

        // 4.开始判断休息时间
        // 4.1先对时间进行整理（跨天+1操作）
        List<Date[]> convertedRestDate = new ArrayList<>();
        if (schedulingTimeConfigDto.getRestTimeJson() != null) {
            List<String> timeArr = JacksonUtils.parseArray(schedulingTimeConfigDto.getRestTimeJson(), String.class);
            for (String t : timeArr) {
                String[] se = t.split("-");
                if (se[0].compareTo(se[1]) > 0) {
                    // 跨天
                    convertedRestDate.add(new Date[]{simpleDateFormat.parse(se[0]), new Date(simpleDateFormat.parse(se[1]).getTime() + 24L * 60 * 60 * 1000)});
                } else {
                    // 不跨天 看在第一天还是第二天
                    if (se[0].compareTo(schedulingTimeConfigDto.getWorkTime()) > 0) {
                        // 第一天
                        convertedRestDate.add(new Date[]{simpleDateFormat.parse(se[0]), new Date(simpleDateFormat.parse(se[1]).getTime())});
                    } else {
                        // 第二天
                        convertedRestDate.add(new Date[]{new Date(simpleDateFormat.parse(se[0]).getTime() + 24L * 60 * 60 * 1000), new Date(simpleDateFormat.parse(se[1]).getTime() + 24L * 60 * 60 * 1000)});
                    }
                }
            }
        }
        // 4.2循环比较发现有一个休息时间段不在工作时间段之内就报错
        for (int i = 0; i < convertedRestDate.size(); i++) {
            // 和上下班时间对比
            if (convertedRestDate.get(i)[0].getTime() < workTime
                    || convertedRestDate.get(i)[1].getTime() > closeTime
            ) {
                return Response.error("休息时间段必须在工作时间段");
            }
        }

        for (int i = 0; i < convertedRestDate.size(); i++) {
            for (int j = i+1; j < convertedRestDate.size(); j++) {
                if (DateUtil.isOverlap(
                        convertedRestDate.get(i)[0],convertedRestDate.get(i)[1],
                        convertedRestDate.get(j)[0],convertedRestDate.get(j)[1]
                        )
                ) {
                    return Response.error("休息时间段不能重合");
                }

            }
        }

        return Response.ok();
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @PostMapping("delete")
    @RequirePermissions(values = "schedulingTimeConfig:delete")
    @Operation(summary = "根据多条记录id批量删除考勤时间段配置")
    public Response<Object> delete(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (schedulingTimeConfigService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
        }

        schedulingTimeConfigService.deleteBatch(ids);

        return Response.ok();
    }
}
